<template>
    <div ref="tableSelectRef" :style="'width:' + width">
        <el-popover
            :visible="popoverVisible"
            :width="popoverWidth"
            placement="bottom-end"
            v-bind="selectConfig.popover"
            @show="handleShow"
        >
            <template #reference>
                <div @click="popoverVisible = !popoverVisible">
                    <slot>
                        <el-input class="reference" :model-value="text" :readonly="true" :placeholder="placeholder">
                            <template #suffix>
                                <el-icon
                                    :style="{
                                        transform: popoverVisible ? 'rotate(180deg)' : 'rotate(0)',
                                        transition: 'transform .5s'
                                    }"
                                >
                                    <ArrowDown />
                                </el-icon>
                            </template>
                        </el-input>
                    </slot>
                </div>
            </template>
            <!-- 弹出框内容 -->
            <div ref="popoverContentRef">
                <!-- 表单 -->
                <el-form ref="formRef" :model="queryParams" :inline="true">
                    <template v-for="item in selectConfig.formItems" :key="item.prop">
                        <el-form-item :label="item.label" :prop="item.prop">
                            <!-- Input 输入框 -->
                            <template v-if="item.type === 'input'">
                                <template v-if="item.attrs?.type === 'number'">
                                    <el-input
                                        v-model.number="queryParams[item.prop]"
                                        v-bind="item.attrs"
                                        @keyup.enter="handleQuery"
                                    />
                                </template>
                                <template v-else>
                                    <el-input
                                        v-model="queryParams[item.prop]"
                                        v-bind="item.attrs"
                                        @keyup.enter="handleQuery"
                                    />
                                </template>
                            </template>
                            <!-- Select 选择器 -->
                            <template v-else-if="item.type === 'select'">
                                <el-select v-model="queryParams[item.prop]" v-bind="item.attrs">
                                    <template v-for="option in item.options" :key="option.value">
                                        <el-option :label="option.label" :value="option.value" />
                                    </template>
                                </el-select>
                            </template>
                            <!-- TreeSelect 树形选择 -->
                            <template v-else-if="item.type === 'tree-select'">
                                <el-tree-select v-model="queryParams[item.prop]" v-bind="item.attrs" />
                            </template>
                            <!-- DatePicker 日期选择器 -->
                            <template v-else-if="item.type === 'date-picker'">
                                <el-date-picker v-model="queryParams[item.prop]" v-bind="item.attrs" />
                            </template>
                            <!-- Input 输入框 -->
                            <template v-else>
                                <template v-if="item.attrs?.type === 'number'">
                                    <el-input
                                        v-model.number="queryParams[item.prop]"
                                        v-bind="item.attrs"
                                        @keyup.enter="handleQuery"
                                    />
                                </template>
                                <template v-else>
                                    <el-input
                                        v-model="queryParams[item.prop]"
                                        v-bind="item.attrs"
                                        @keyup.enter="handleQuery"
                                    />
                                </template>
                            </template>
                        </el-form-item>
                    </template>
                    <el-form-item>
                        <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
                        <el-button icon="refresh" @click="handleReset">重置</el-button>
                    </el-form-item>
                </el-form>
                <!-- 列表 -->
                <el-table
                    ref="tableRef"
                    v-loading="loading"
                    :data="pageData"
                    :border="true"
                    :max-height="250"
                    :row-key="pk"
                    :highlight-current-row="true"
                    :class="{ radio: !isMultiple }"
                    @select="handleSelect"
                    @select-all="handleSelectAll"
                >
                    <template v-for="col in selectConfig.tableColumns" :key="col.prop">
                        <!-- 自定义 -->
                        <template v-if="col.templet === 'custom'">
                            <el-table-column v-bind="col">
                                <template #default="scope">
                                    <slot :name="col.slotName ?? col.prop" :prop="col.prop" v-bind="scope"></slot>
                                </template>
                            </el-table-column>
                        </template>
                        <!-- 其他 -->
                        <template v-else>
                            <el-table-column v-bind="col" />
                        </template>
                    </template>
                </el-table>
                <!-- 分页 -->
                <pagination
                    v-if="total > 0"
                    v-model:total="total"
                    v-model:page="queryParams.pageCurrent"
                    v-model:limit="queryParams.pageSize"
                    @pagination="handlePagination"
                />
                <div class="feedback">
                    <el-button type="primary" size="small" @click="handleConfirm">
                        {{ confirmText }}
                    </el-button>
                    <el-button size="small" @click="handleClear">清 空</el-button>
                    <el-button size="small" @click="handleClose">关 闭</el-button>
                </div>
            </div>
        </el-popover>
    </div>
</template>

<script lang="ts" setup>
import { ref, reactive, computed } from 'vue'
import { onClickOutside, useResizeObserver } from '@vueuse/core'
import type { FormInstance, PopoverProps, TableInstance } from 'element-plus'

// 对象类型
export type IObject = Record<string, any>
// 定义接收的属性
export interface ISelectConfig<T = any> {
    // 宽度
    width?: string
    // 占位符
    placeholder?: string
    // popover组件属性
    popover?: Partial<Omit<PopoverProps, 'visible' | 'v-model:visible'>>
    // 列表的网络请求函数(需返回promise)
    indexAction: (queryParams: T) => Promise<any>
    // 主键名(跨页选择必填,默认为id)
    pk?: string
    // 多选
    multiple?: boolean
    // 表单项
    formItems: Array<{
        // 组件类型(如input,select等)
        type?: 'input' | 'select' | 'tree-select' | 'date-picker'
        // 标签文本
        label: string
        // 键名
        prop: string
        // 组件属性
        attrs?: IObject
        // 初始值
        initialValue?: any
        // 可选项(适用于select组件)
        options?: { label: string; value: any }[]
    }>
    // 列选项
    tableColumns: Array<{
        type?: 'default' | 'selection' | 'index' | 'expand'
        label?: string
        prop?: string
        width?: string | number
        [key: string]: any
    }>
}
const props = withDefaults(
    defineProps<{
        selectConfig: ISelectConfig
        text?: string
    }>(),
    {
        text: ''
    }
)

// 自定义事件
const emit = defineEmits<{
    confirmClick: [selection: any[]]
}>()

// 主键
const pk = props.selectConfig.pk ?? 'id'
// 是否多选
const isMultiple = props.selectConfig.multiple === true
// 宽度
const width = props.selectConfig.width ?? '100%'
// 占位符
const placeholder = props.selectConfig.placeholder ?? '请选择'
// 是否显示弹出框
const popoverVisible = ref(false)
// 加载状态
const loading = ref(false)
// 数据总数
const total = ref(0)
// 列表数据
const pageData = ref<IObject[]>([])
// 每页条数
const pageSize = 10
// 搜索参数
const queryParams = reactive<{
    pageCurrent: number
    pageSize: number
    [key: string]: any
}>({
    pageCurrent: 1,
    pageSize: pageSize
})

// 计算popover的宽度
const tableSelectRef = ref()
const popoverWidth = ref(width)
useResizeObserver(tableSelectRef, entries => {
    popoverWidth.value = `${entries[0].contentRect.width}px`
})

// 表单操作
const formRef = ref<FormInstance>()
// 初始化搜索条件
for (const item of props.selectConfig.formItems) {
    queryParams[item.prop] = item.initialValue ?? ''
}
// 重置操作
function handleReset() {
    formRef.value?.resetFields()
    fetchPageData(true)
}
// 查询操作
function handleQuery() {
    fetchPageData(true)
}

// 获取分页数据
function fetchPageData(isRestart = false) {
    loading.value = true
    if (isRestart) {
        queryParams.pageCurrent = 1
        queryParams.pageSize = pageSize
    }
    props.selectConfig
        .indexAction(queryParams)
        .then(data => {
            total.value = data.total
            pageData.value = data.list
        })
        .finally(() => {
            loading.value = false
        })
}

// 列表操作
const tableRef = ref<TableInstance>()
// 数据刷新后是否保留选项
for (const item of props.selectConfig.tableColumns) {
    if (item.type === 'selection') {
        item.reserveSelection = true
        break
    }
}
// 选择
const selectedItems = ref<IObject[]>([])
const confirmText = computed(() => {
    return selectedItems.value.length > 0 ? `已选(${selectedItems.value.length})` : '确 定'
})
function handleSelect(selection: any[], row: any) {
    if (isMultiple || selection.length === 0) {
        // 多选
        selectedItems.value = selection
    } else {
        // 单选
        selectedItems.value = [selection[selection.length - 1]]
        tableRef.value?.clearSelection()
        tableRef.value?.toggleRowSelection(selectedItems.value[0], true)
        tableRef.value?.setCurrentRow(selectedItems.value[0])
    }
}
function handleSelectAll(selection: any[]) {
    if (isMultiple) {
        selectedItems.value = selection
    }
}
// 分页
function handlePagination() {
    fetchPageData()
}

// 弹出框
const isInit = ref(false)
// 显示
function handleShow() {
    if (isInit.value === false) {
        isInit.value = true
        fetchPageData()
    }
}
// 确定
function handleConfirm() {
    if (selectedItems.value.length === 0) {
        ElMessage.error('请选择数据')
        return
    }
    popoverVisible.value = false
    emit('confirmClick', selectedItems.value)
}
// 清空
function handleClear() {
    tableRef.value?.clearSelection()
    selectedItems.value = []
}
// 关闭
function handleClose() {
    popoverVisible.value = false
}
const popoverContentRef = ref()
/* onClickOutside(tableSelectRef, () => (popoverVisible.value = false), {
  ignore: [popoverContentRef],
}); */
</script>

<style scoped lang="scss">
.reference :deep(.el-input__wrapper),
.reference :deep(.el-input__inner) {
    cursor: pointer;
}

.feedback {
    display: flex;
    justify-content: flex-end;
    margin-top: 6px;
}
// 隐藏全选按钮
.radio :deep(.el-table__header th.el-table__cell:nth-child(1) .el-checkbox) {
    visibility: hidden;
}
</style>
